package com.mt.vsphere.core.zhu.security;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Component;
import org.springframework.util.ReflectionUtils;
import org.springframework.web.bind.annotation.*;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

//TODO 加入自定义安全认证注解 在RequesstMapping方法中加入注解即可使的此url，在HTTP请求到来的时候进行自动的认证
@Component
public class AuthScanner implements BeanPostProcessor {

    private final List<Class<? extends Annotation>> authAnnotations = Arrays.asList(Auth.class);
    private Map<String,AuthRole> urlRoleMap = new HashMap<>();
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

    public Map<String, AuthRole> getUrlRoleMap() {
        return urlRoleMap;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        String prefix = "";
        //由于springContent是CGLIB代理类 所有不能用jdk的方法获取 直接使用spring的AnnotationUtils获取
        RequestMapping requestMapping = AnnotationUtils.findAnnotation(bean.getClass(), RequestMapping.class);
        if (requestMapping!=null){
            prefix+= requestMapping.value()[0];
        }
        final String finalPrefix = prefix;
        ReflectionUtils.doWithMethods(bean.getClass(),(Method method)->{
            for (Class<? extends Annotation> annotation:authAnnotations){
                if (method.getAnnotation(annotation) != null){
                    if (method.getAnnotation(annotation).annotationType() == Auth.class){
                        Auth auth = method.getAnnotation(Auth.class);
                        String path = getPath(method);
                        urlRoleMap.put(finalPrefix+path,auth.role());
                    }
                }
            }
            method.getAnnotation(Auth.class);
        },(Method method)->{
            for (Class<? extends Annotation> annotation:authAnnotations){
                if (method.isAnnotationPresent(annotation)){
                    return true;
                }
            }
            return false;
        });
        return bean;
    }

    @SuppressWarnings("all")
    private String getPath(Method method){
        RequestMapping requestMapping = AnnotationUtils.getAnnotation(method, RequestMapping.class);
        if (requestMapping  == null){
            throw new NullPointerException("RequestMapping注解不存在或没有赋值");
        }
        RequestMethod httpMethod = requestMapping.method()[0];
        String path;
        switch (httpMethod){
            case GET:
                path = AnnotationUtils.getAnnotation(method, GetMapping.class).value()[0];
                break;
            case POST:
                path = AnnotationUtils.getAnnotation(method, PostMapping.class).value()[0];
                break;
            case PUT:
                path = AnnotationUtils.getAnnotation(method, PutMapping.class).value()[0];
                break;
            case DELETE:
                path = AnnotationUtils.getAnnotation(method, DeleteMapping.class).value()[0];
                break;
            default:
                path = requestMapping .value()[0];
        }
        return path;
    }

}
